import { Injectable, NgZone, Inject, Optional } from '@angular/core';
import { Title } from '@angular/platform-browser';

import { LoggerService } from './logger.service';
import { StoreService } from './store.service';
import { BroadcastService } from './broadcast.service';
import { ApplicationEnv, SESSION_CHECK_WHITELIST_PAGES, SESSION_EXPIRY_TIME, MATH_SCRIPT_PATHS, LOGGER_REWRITE_NATIVE_METHOD, CLIPBOARD_SCRIPT_PATHS, SPA } from '../keys';
import { AppService } from './app.service';
import { PlatformLocation } from '@angular/common';
import { LazyLoaderService } from './lazy-loader.service';

@Injectable({
  providedIn: 'root'
})
export class StartupService<U, B, S> {

  constructor(
    private loggerService: LoggerService,
    private storeService: StoreService<B, S>,
    private broadcastService: BroadcastService<B>,
    private title: Title,
    private ngZone: NgZone,
    private applicationEnv: ApplicationEnv,
    private appService: AppService<U, B, S>,
    @Optional() @Inject(SESSION_CHECK_WHITELIST_PAGES) private sessionWhiteListPages: string[] = [],
    private location: PlatformLocation,
    @Optional() @Inject(SESSION_EXPIRY_TIME) private sessionExpiryTime: number,
    private lazyLoaderService: LazyLoaderService,
    @Inject(MATH_SCRIPT_PATHS) private mathScriptPaths: string[],
    @Inject(LOGGER_REWRITE_NATIVE_METHOD) private isRewriteNativeMethod: boolean,
    @Optional() @Inject(SPA) private spa: boolean,
    @Optional() @Inject(CLIPBOARD_SCRIPT_PATHS) private clipbardScriptPaths: string[]
  ) {

    this.spa = window.self === window.top ? (this.spa === null ? false : this.spa) : true;
  }

  /**
   * checkSession: 是否开启session校验
  */
  run(isCheckSession = true) {
    // 开始搜集页面信息，监控页面报错信息
    if (this.isRewriteNativeMethod === true) {
      this.loggerService.rewriteNativeMethod();
    }
    // 加载本地数据到缓存
    this.storeService.loadData();
    // 拦截页面点击事件
    window.document.body.addEventListener('click', (event) => {
      this.broadcastService.emit(<any>'GlobalClick', event);
    }, true);

    if (!this.spa) {
      this.broadcastService.subscribe(<any>'StoreChange', (data) => {
        if (data.key === 'BaseInfo' && data.newValue && data.newValue.title !== this.title.getTitle()) {
          this.title.setTitle(data.newValue.title);
        }
      });
      const baseInfo = this.storeService.getItem(<any>'BaseInfo');
      // 设置页面title
      this.ngZone.runOutsideAngular(() => {
        setTimeout(() => {
          if (baseInfo && baseInfo.title) {
            this.title.setTitle(baseInfo.title);
          }
        });
      });

      // 验证session是否有效
      if (isCheckSession) {
        this.checkSession();
      }
    }
    this.choreTask();
  }

  private checkSession() {
    const currUrl = window.location.pathname.replace(this.location.getBaseHrefFromDOM(), '/');
    const entryTime = this.storeService.getItem(<any>'EntryTime');
    const baseInfo = this.storeService.getItem(<any>'BaseInfo');
    const entryExpiry = !entryTime || ((Date.now() - entryTime) / (1000 * 60 * 60) >= this.sessionExpiryTime);

    let ignore = false;
    // 过滤白名单页面
    const swlp = this.sessionWhiteListPages;
    for (let i = 0; i < swlp.length; i++) {
      const page = swlp[i];
      const pageRex = new RegExp(page, 'i');
      if (pageRex.test(currUrl)) {
        ignore = true;
        break;
      }
    }

    // 如果当前页面不在会话校验白名单中，同时上一次的认证时间已经超时失效，或者没有baseInfo信息，直接跳转到认证页面
    if (!ignore && (entryExpiry || !baseInfo)) {
      this.appService.storeSession();
      window.location.href = this.applicationEnv.authUrl;
    }
  }

  private choreTask() {
    this.lazyLoaderService.register('mathjs', {
      corePaths: this.mathScriptPaths, helper: {
        calc: (expression, precision) => {
          const math = (window as any).math;
          const result = math.format(math.eval(expression), precision || 6);
          return result;
        }
      }
    });

    if (Array.isArray(this.clipbardScriptPaths)) {
      this.lazyLoaderService.register('clipboard', {
        corePaths: this.clipbardScriptPaths
      });
    }
  }
}
